package org.jeecg.modules.simulator.model.train;

import org.jeecg.modules.simulator.model.orbit.OrbitPoint;
import lombok.Getter;
import lombok.Setter;
import org.jeecg.modules.simulator.vo.TrainPosition;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @program:
 * @description: 列车业务类
 * @author: lydms
 * @create: 2024-08-07 09:34
 **/
public class TrainBiz {

    /**
     * 业务属性
     */
    @Getter
    @Setter
    String currentSectName;//当前停靠运行区间

    @Getter
    @Setter
    private Double currentSpeed;


    Boolean isPositive;//是否正向运行

    //    //当前坐标位置
    @Setter
    @Getter
    Long currentOpt = 0L;
    //    //当前坐标位置
    Long nextOpt = 0L;
    @Setter
    @Getter
    Integer timeCount=0;



    @Getter
    @Setter
    Integer actionTimeCount=0;


//    Integer sublevelCount = 0;

    //正在使用区间和站点的编号名称
    String currentOPointKey;
    @Getter
    @Setter
    private TrainRunState state;//车辆状态

    public TrainBiz(Map<String, OrbitPoint> orbitPoints) {
        this.orbitPoints = orbitPoints;//所有轨道数据

    }

    List<Double> sublevelList = new LinkedList<>();//sect分段，用链表存储的数据，数值就是每秒移动的距离

    //region 结构化的属性
    Map<String, OrbitPoint> orbitPoints;//车辆路径,变成一个由编号的组成的map，给编号查询区间和站点IU行了

    ListIterator<Double> sublevelIterator = sublevelList.listIterator();


    @Getter
    @Setter
    private TrainRunState lastState;//车辆状态
//endregion

    /**
     * 获取指定名称的轨道终点偏��距离
     *
     * @param name 轨道名称
     * @return 终点偏移距离
     */
    public Long getOffset(String name) {
        return this.orbitPoints.get(name).getEndOffsetDistance();
    }


    public Long getAllOrbitLastOffset() {
        List<OrbitPoint> orbitPoints = new ArrayList<>(this.orbitPoints.values());
        Collections.sort(orbitPoints);
        return orbitPoints.get(orbitPoints.size()-1).getEndOffsetDistance();
    }

    //计算当前位置

    /**
     * @description: 得到当前动作下坐标偏移
     * @author: renzhg
     * @date: 2024/8/12 9:22
     **/
    public Long getCurActionOffset(Long seconds) {
        return seconds *  Math.round(this.currentSpeed);
    }


    /**
     * 功能描述：调度员可以设置车站暂停
     *
     * @author renowen2005
     * @date 2024/07/24
     */
    public void setTrainStop() {
        this.state = TrainRunState.stop;
    }

    /**
     * 下一个点是否可以运行
     *
     * @return
     */
    public Boolean canNextRun() {
        return sublevelIterator.hasNext();
    }

    /**
     * @description: 列车在正向区间运行动作
     * @author: renzhg
     * @date: 2024/7/30 9:31
     **/
    public void handlePositiveSection() {
        this.currentOpt += nextOpt; // 坐标赋值
    }
    /**
     * @description: 列车在反向区间运行动作
     * @author: renzhg
     * @date: 2024/7/30 9:31
     **/
    public void handleNegativeSection(){
        this.currentOpt -= nextOpt;
    }

    /**
     * 更新列车状态
     */
    public void update(LocalTime localTime,LocalTime endlocalTime) {


        if (this.state == TrainRunState.nextrun) {
            if (canNextRun()&&localTime.isBefore(endlocalTime)) {
                nextOpt = Math.round(sublevelIterator.next());
                this.timeCount++;
//                if(isPositive){
                handlePositiveSection();
//                }else{
//                    handleNegativeSection();
//                }

            } else {
                this.state = TrainRunState.stop;

            }
        }
    }


    public OrbitPoint getOrbitPoint(String key) {

        return this.orbitPoints.get(key);
    }

//    /**
//     * 获取当前位置
//     *
//     * @param trainId  列车ID
//     * @param trainNum 列车编号
//     * @param time     时间
//     */
//    public TrainPosition getCurrentPosition(String trainId,String lineId, String trainNum, String time) {
//        if(trainId.equals("106")&&trainNum.equals("03")&&lineId.equals("04")){
//            System.out.println("TrainBiz-----getCurrentPosition---当前列车编号："+trainId+"_"+trainNum);
//        }
////        System.out.println("TrainBiz-----getCurrentPosition---当前列车编号："+trainId+"_"+trainNum);
//        List<OrbitPoint> orbitPoints = new ArrayList<>(this.orbitPoints.values());
//        Collections.sort(orbitPoints);
//        List<OrbitPoint> orbitPointList=filterOrbitPoints(orbitPoints, this.currentOpt);
//        if(orbitPointList.isEmpty()){
//            return null;
//        }
//        OrbitPoint orbitPoint = orbitPointList.get(0);
//        TrainPosition trainPosition = new TrainPosition();
//        trainPosition.setTrainId(trainId);
//        trainPosition.setTrainNum(trainNum);
//        trainPosition.setOrbitAttr(orbitPoint);
//        trainPosition.setLineId(lineId);
////        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
////        String timeString = time.format(formatter);
//
//        if(orbitPoint.getBelongingType().equals("station")){
//            trainPosition.setPositionRatio(new BigDecimal(0));
//            trainPosition.setCurTime(time);
//            trainPosition.setCurrentOpt(this.currentOpt);
//            return trainPosition;
//        }else{
//            caculateRatio(orbitPoint);
//
//            trainPosition.setCurTime(time);
//            trainPosition.setCurrentOpt(this.currentOpt);
//            return trainPosition;
//        }
//
//    }

    public  BigDecimal caculateRatio(OrbitPoint orbitPoint) {
        BigDecimal timeCount = new BigDecimal(this.timeCount);

        BigDecimal actionTimeCount = new BigDecimal(this.actionTimeCount);
        return timeCount.divide(actionTimeCount, 2, RoundingMode.HALF_UP);
//        BigDecimal startNum = new BigDecimal(orbitPoint.getStartOffsetDistance());
//        BigDecimal denom = new BigDecimal(orbitPoint.getDistance());
//        if (this.currentOpt.equals(orbitPoint.getStartOffsetDistance())) {
//           return new BigDecimal(0);
//        } else {
//            BigDecimal result = num.subtract(startNum);
//
//        }
    }

    public  List<OrbitPoint> filterOrbitPoints(List<OrbitPoint> points,Long currentOpt) {
        List<OrbitPoint> filteredPoints = new ArrayList<>();

        for (OrbitPoint point : points) {
            if (point.getStartOffsetDistance() <= currentOpt && point.getEndOffsetDistance() >= currentOpt||point.getEndOffsetDistance() <= currentOpt && point.getStartOffsetDistance() >= currentOpt) {
                filteredPoints.add(point);
            }
        }

        return filteredPoints;
    }
    /**
     * @description: 简单运行获取全部的轨道长度
     * @author: renzhg
     * @date: 2024/9/24 10:36
     **/
    public Long getAllOrbitLength() {
        List<OrbitPoint> orbitPoints = new ArrayList<>(this.orbitPoints.values());
        Collections.sort(orbitPoints);
        return orbitPoints.get(orbitPoints.size()-1).getEndOffsetDistance() - orbitPoints.get(0).getEndOffsetDistance();
    }


    public Long getSimpleTrainStartOrbitLength(){
        List<OrbitPoint> orbitPoints = new ArrayList<>(this.orbitPoints.values());
        Collections.sort(orbitPoints);
        if(orbitPoints.get(orbitPoints.size()-1).getEndOffsetDistance() - orbitPoints.get(0).getEndOffsetDistance()<0){
            return  orbitPoints.get(0).getEndOffsetDistance();
        }else{
            return  orbitPoints.get(orbitPoints.size()-1).getEndOffsetDistance();
        }
    }



    /**
     * @description: 简单运行初始化
     * @author: renzhg
     * @date: 2024/9/24 10:36
     **/
    public Long initSimpleStart(Double speed) {
        long during = 0L;
        if (speed != 0L) {

            this.currentSpeed = speed;

        }
        long orbitLenth = getAllOrbitLength();
        this.timeCount=0;

        this.currentOpt = getSimpleTrainStartOrbitLength();
        during =Math.round(orbitLenth / speed) ;
        this.actionTimeCount=(int) during;
        initSublevelList(during);
        sublevelIterator = sublevelList.listIterator();
        return during;
    }


    public void initOneTimePtSectStart(String sectname, long time, long passTime) {
        this.currentSectName = sectname;
        OrbitPoint orbitPoint = this.orbitPoints.get(sectname);
        calculateSpeed(orbitPoint.getDistance(), time);
        initOneTimePtSublevelList(time, passTime);

        this.state = TrainRunState.nextrun;
    }


    public void initOneTimePtStopStart(String stopName) {
      this.orbitPoints.get(stopName);

        this.state = TrainRunState.stop;
    }

    /**
     * 初始化起始点
     *
     * @param sectname 区间名称
     * @param time     时间
     */
    public void initStart(String sectname, long time) {
        if(sectname.equals("丁香湖-元江街")){
            System.out.println("fdasfafdasd");
        }
        if(sectname.equals("北大营-合作街")){
            System.out.println("fdasfafdasd");
        }

        this.currentSectName = sectname;
        OrbitPoint orbitPoint = this.orbitPoints.get(sectname);
        this.currentOpt = orbitPoint.getStartOffsetDistance();
        this.timeCount=0;

        this.actionTimeCount=(int) time;
//        this.currentOpt = orbitPoint.getStartOffsetDistance();
        calculateSpeed(orbitPoint.getDistance(), time);
        initSublevelList(time);
        isPositive=orbitPoint.getIsPositive();
        sublevelIterator = sublevelList.listIterator();
    }

    /**
     * 初始化区间分段列表
     *
     * @param time 时间
     */
    public void initSublevelList(long time) {
//        this.sublevelCount = 0;
        if(time<0){

            for (int i = 0; i < Math.abs(time); i++) {
                sublevelList.add(-this.currentSpeed);
            }
            return;
        }
        this.sublevelList.clear();
        for (int i = 0; i < time; i++) {
            sublevelList.add(this.currentSpeed);
        }


    }

    public void initOneTimePtSublevelList(long time, long beforeTime) {
        for (int i = 0; i < time; i++) {
            sublevelList.add(this.currentSpeed);
        }
        sublevelIterator = sublevelList.listIterator();

        for (int m = 0; m < beforeTime; m++) {
            nextOpt = Math.round(sublevelIterator.next());
            this.currentOpt += nextOpt;
        }

    }


    /**
     * 计算速度
     *
     * @param distance 距离
     * @param time     时间
     */
    public void calculateSpeed(long distance, long time) {

        if (time != 0) { // Check to prevent division by zero
            this.currentSpeed =  (double) distance / time;
        } else {
            this.currentSpeed = 0.0;

        }

    }

}
